<script setup lang="ts">
import { ref } from "vue";
import type { Ref } from "vue";
import type { MenuItem } from "@/utils/router-menu";
import { scannable, scanMenuFromRoutes } from "./menu-scan";
import { YiTable, YiAction } from "@uublue/yimi-element-plus";
import pinia from "@/stores/index";

import { actionAxios } from "@/utils/request";
import MenuForm from "./menu-form.vue";
import ApiDisplay from "../api/api-display.vue";
import SecurityDisplay from "../api/security-display.vue";
import { forEachRecursively, mapRecursively } from "@/utils/array-recursion";
import { usePage } from "@/stores/page";

const pageStore = usePage(pinia);
const initialMenu: Ref<MenuItem[]> = ref([]);
const menuItemGroupOptions: Ref<Record<string, any>[]> = ref([]);
const menuOptions: Ref<Record<string, any>[]> = ref([]);
const selectedMenu = ref();
const menuTableExpandAll = ref(false);
const apiTable: Ref<typeof YiTable | undefined> = ref();

//on create
loadMenuGroups();

// methods
function setMenuOptions(res: any) {
  menuOptions.value = mapRecursively(res.data?.rows as any[], (menuItem) => {
    return {
      value: menuItem.id,
      label: menuItem.name,
      type: menuItem.type,
      children: menuItem.children,
    };
  });
}

function refreshApiTable() {
  if (selectedMenu.value) {
    apiTable.value?.refresh({
      params: { pagePath: selectedMenu.value?.pagePath },
    });
  } else {
    apiTable.value?.clear();
  }
}

function loadMenuGroups() {
  actionAxios.request(getMenuGroups).then((res) => {
    menuItemGroupOptions.value = mapRecursively(
      res.data as any[],
      (menuGroup) => {
        return {
          value: menuGroup.code,
          label: menuGroup.label,
          children: menuGroup.children,
        };
      },
    );
  });
}

function apiResAdapter(res: any) {
  return {
    rows: (res.data?.rows || []).map((row: Record<string, any>) => {
      return {
        name: row.name,
        antPattern: row.api?.antPattern,
        method: row.api?.method,
        permissions: row.api.permissions,
        roles: row.api.roles,
      };
    }),
  };
}

async function prepareMenu(menuGroup: string) {
  const menu = await scanMenuFromRoutes(menuGroup);
  initialMenu.value = menu;
  return menu;
}
</script>

<!-- 定义api -->
<script lang="ts">
import menuApis from "@/apis/system/menu";

const {
  syncMenu,
  getMenuTree,
  addMenuItem,
  updateMenuItem,
  removeMenuItem,
  getMenuPageApis,
  getMenuGroups,
  addMenuGroup,
} = menuApis;
export default {
  name: "MenuView",
  apis: {
    syncMenu,
    getMenuTree,
    addMenuItem,
    updateMenuItem,
    removeMenuItem,
    getMenuPageApis,
    getMenuGroups,
    addMenuGroup,
  },
};
</script>

<template>
  <div class="app-container">
    <el-row :gutter="20">
      <!--菜单数据-->
      <el-col :span="16" :xs="0">
        <yi-table
          :api="getMenuTree"
          :tools="['refresh']"
          :model="{ group: 'local' }"
          class="menu-table"
          :columns="[
            {
              label: '菜单名称',
              prop: 'title',
              showOverflowTooltip: true,
              slot: 'title',
            },
            {
              label: '请求地址',
              prop: 'url',
              showOverflowTooltip: true,
              formatter: (row, column, cellValue) => {
                if (row.type == 'Directory') {
                  return '-';
                } else {
                  return cellValue;
                }
              },
            },
            {
              label: '菜单类型',
              prop: 'type',
              width: 80,
              formatter: (row, column, cellValue) => {
                if (cellValue == 'Directory') {
                  return '目录';
                } else if (cellValue == 'Page') {
                  return '页面';
                } else if (cellValue == 'ExternalLink') {
                  return '外部链接';
                }
              },
            },
            {
              label: '权限标识',
              showOverflowTooltip: true,
              prop: 'permission',
            },
            {
              label: '对应页面',
              headerAlign: 'center',
              prop: 'pagePath',
              slot: 'pagePath',
            },

            {
              label: '操作',
              prop: 'opt',
              slot: 'opt',
            },
          ]"
          default-expand-all
          highlight-current-row
          :paged="false"
          @on-search-success="
            (res) => {
              setMenuOptions(res);
            }
          "
          @current-row-change="
            (currentRow) => {
              if (!currentRow) {
                selectedMenu = undefined;
              } else if (currentRow.type == 'Page') {
                selectedMenu = currentRow;
              } else {
                selectedMenu = undefined;
              }
              refreshApiTable();
            }
          "
        >
          <template #actions="{ refresh, model }">
            <el-row>
              <el-select
                v-model="model.group"
                placeholder="选择菜单组"
                size="small"
                style="width: 240px"
                @change="refresh"
              >
                <el-option
                  v-for="(item, index) in menuItemGroupOptions"
                  :key="index"
                  :label="item.label"
                  :value="item.value"
                />

                <template #header>
                  <yi-action
                    :api="addMenuGroup"
                    size="small"
                    circle
                    icon="el-icon-plus"
                    :mix-model="
                      (model, mix) => {
                        mix({
                          params: {
                            code: model.code,
                            label: model.label,
                          },
                        });
                      }
                    "
                    model-reserve="never"
                    modal-title="添加菜单组"
                    dialog-width="700px"
                    @on-submit-success="refresh"
                  >
                    <template #default="{ form, model: model1 }">
                      <el-form
                        :ref="form"
                        :model="model1"
                        label-position="right"
                        label-width="100px"
                      >
                        <el-form-item label="组名" prop="label" required>
                          <el-input
                            v-model="model1.label"
                            placeholder="请输入菜单组名"
                          />
                        </el-form-item>
                        <el-form-item label="组编码" prop="code" required>
                          <el-input
                            v-model="model1.code"
                            placeholder="请输入菜单组编码"
                          />
                        </el-form-item>
                      </el-form>
                    </template>
                  </yi-action>
                </template>
              </el-select>

              <!-- 新增 -->
              <yi-action
                :api="
                  () => {
                    return addMenuItem({ group: model.group });
                  }
                "
                text="新增"
                type="primary"
                size="small"
                :plain="true"
                icon="el-icon-plus"
                style="margin-left: 12px"
                modal-title="添加菜单"
                dialog-width="700px"
                @on-submit-success="refresh"
              >
                <template #default="scope">
                  <menu-form
                    v-model="scope.model"
                    :form-ref="scope.form"
                    :menu-options="menuOptions"
                    use-for="add"
                  />
                </template>
              </yi-action>

              <!-- 同步菜单 -->
              <yi-action
                v-if="scannable(model.group)"
                :api="syncMenu"
                text="同步菜单"
                type="danger"
                size="small"
                :plain="true"
                icon="el-icon-upload-filled"
                modal-title="菜单初始化"
                dialog-width="80%"
                :on-open="
                  ({ model: actionModel, context, resolve }) => {
                    prepareMenu(model.group).then(() => {
                      resolve();
                    });
                  }
                "
                :on-submit="
                  (scope, request, close) => {
                    request({
                      data: initialMenu,
                      params: {
                        group: model.group,
                      },
                    }).then(() => {
                      close();
                    });
                  }
                "
                @on-submit-success="refresh"
              >
                <template #default>
                  <yi-table
                    row-key="path"
                    class="menu-table"
                    :columns="[
                      {
                        label: '菜单名',
                        prop: 'title',
                        slot: 'title',
                      },
                      {
                        label: '路由地址',
                        prop: 'url',
                      },
                      {
                        label: '权限标识',
                        prop: 'permission',
                      },
                      {
                        label: '对应页面',
                        headerAlign: 'center',
                        slot: 'pagePath',
                      },
                    ]"
                    :tools="[]"
                    max-height="650px"
                    :border="true"
                    default-expand-all
                    :data="initialMenu"
                  >
                    <template #title="{ row }">
                      <i
                        v-if="row.meta && row.meta.icon"
                        :class="row.meta.icon"
                      />
                      <span>{{ row.title || row.name }}</span>
                    </template>
                    <template #pagePath="{ row }">
                      <i
                        v-if="row.type == 'Directory'"
                        class="el-icon-folder-opened"
                      />
                      <el-tag v-else size="default" type="info">{{
                        row.pagePath || "-"
                      }}</el-tag>
                    </template>
                  </yi-table>
                </template>
              </yi-action>
            </el-row>
          </template>

          <template #tools="{ rows, useTableRef }">
            <el-tooltip
              class="item"
              effect="dark"
              content="展开/折叠"
              placement="top"
            >
              <el-button
                circle
                icon="el-icon-sort"
                size="small"
                @click="
                  () => {
                    const table = useTableRef();
                    if (table) {
                      forEachRecursively(rows, (row) => {
                        table.toggleRowExpansion(row, menuTableExpandAll);
                      });
                      menuTableExpandAll = !menuTableExpandAll;
                    }
                  }
                "
              />
            </el-tooltip>
          </template>

          <!-- 自定义列的插槽 -->
          <template #title="{ row }">
            <template v-if="row.type == 'Directory'">
              <i v-if="row.icon" :class="row.icon" />
              <span>{{ row.title || row.name }}</span>
            </template>
            <template v-else>
              <i v-if="row.icon" :class="row.icon" />
              <span>{{ row.title || row.name }}</span>
              <el-tooltip
                class="item"
                effect="dark"
                content="可见用户"
                placement="top"
              >
                <el-link
                  class="el-icon-view"
                  type="primary"
                  :underline="false"
                  style="position: absolute; right: 3px; top: calc(50% - 6px)"
                />
              </el-tooltip>
            </template>
          </template>
          <template #pagePath="{ row }">
            <el-tag v-if="row.type == 'Page'" size="default" type="info">{{
              row.pagePath || "-"
            }}</el-tag>
            <span v-else> - </span>
          </template>
          <template #opt="{ row, refresh }">
            <yi-action
              :api="updateMenuItem"
              type="primary"
              trigger="link"
              :underline="false"
              text="修改"
              size="default"
              icon="el-icon-edit"
              :model="row"
              modal-title="修改菜单"
              dialog-width="700px"
              @on-submit-success="
                (res, model) => {
                  Object.assign(row, model);
                }
              "
            >
              <template #default="scope">
                <menu-form
                  v-model="scope.model"
                  :form-ref="scope.form"
                  :menu-options="menuOptions"
                  use-for="edit"
                />
              </template>
            </yi-action>

            <yi-action
              v-model:loading="pageStore.loading"
              title="删除"
              :api="removeMenuItem(row.id)"
              type="primary"
              trigger="link"
              :underline="false"
              text="删除"
              size="default"
              icon="el-icon-delete"
              confirm-text="是否删除该菜单项及其子项？"
              @on-submit-success="
                (res) => {
                  $message({
                    message: '删除了' + res.data + '个菜单',
                    type: res.data > 0 ? 'success' : 'error',
                  });
                  refresh();
                }
              "
            />
            <yi-action
              v-if="row.type == 'Directory'"
              title="新增子项"
              :api="addMenuItem()"
              type="primary"
              trigger="link"
              :underline="false"
              text="新增"
              size="default"
              icon="el-icon-circle-plus"
              :modal-title="row.name + ' - 新增子项'"
              :model="{ parentId: row.id }"
              dialog-width="700px"
              @on-submit-success="refresh"
            >
              <template #default="scope">
                <menu-form
                  v-model="scope.model"
                  :form-ref="scope.form"
                  :menu-options="menuOptions"
                  use-for="addSub"
                />
              </template>
            </yi-action>
          </template>
        </yi-table>
      </el-col>
      <el-col :span="8" :xs="0">
        <yi-table
          ref="apiTable"
          :init="false"
          :api="getMenuPageApis"
          :tools="[]"
          :columns="[
            {
              label: '操作名称',
              prop: 'name',
              slot: 'name',
            },
            {
              label: '权限标识',
              prop: 'permissions',
              slot: 'permissions',
            },
            {
              label: '所需角色',
              prop: 'roles',
              slot: 'roles',
            },
          ]"
          :res-adapter="apiResAdapter"
        >
          <template #tools>
            <el-tooltip
              class="item"
              effect="dark"
              content="刷新"
              placement="top"
            >
              <el-button
                size="small"
                circle
                icon="el-icon-refresh"
                @click="refreshApiTable"
              />
            </el-tooltip>
          </template>

          <template #name="{ row }">
            <el-popover placement="left" width="180" trigger="hover">
              <api-display
                :api="{
                  antPattern: row.antPattern,
                  method: row.method,
                }"
              />
              <template v-slot:reference>
                <el-link type="info" size="default">{{ row.name }}</el-link>
              </template>
            </el-popover>
            <el-tooltip
              class="item"
              effect="dark"
              content="可见用户"
              placement="top"
            >
              <el-link
                class="el-icon-view"
                type="primary"
                :underline="false"
                style="position: absolute; right: 3px; top: calc(50% - 6px)"
              />
            </el-tooltip>
          </template>
          <template #permissions="{ row }">
            <security-display :codes="row.permissions" />
          </template>
          <template #roles="{ row }">
            <security-display :codes="row.roles" />
          </template>
        </yi-table>
      </el-col>
    </el-row>
  </div>
</template>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.menu-table .el-table__expand-icon {
  width: 20px !important;
}
</style>
